package com.aiwu.utils

import com.aiwu.library.util.IOUtil
import com.aiwu.library.util.OtherUtil
import org.apache.tools.zip.ZipEntry
import org.apache.tools.zip.ZipFile
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.IOException

object GameIdUtil {
    private const val GAME_ID_HEX_TAG = "4E434348"

    /**
     * long转16位的16进制大写字符串
     */
    fun convertGameId(gameId: Long): String {
        return gameId.toString(16).padStart(16, '0').uppercase()
    }

    /**
     * 16进制字符串转long
     */
    fun convertGameId(gameIdHex: String): Long {
        return gameIdHex.toLong(16)
    }

    fun getGameId(romFilePath: String?): String? {
        if (romFilePath.isNullOrEmpty()) {
            return null
        }
        val romFile = File(romFilePath)
        val gameIdCacheFile = getGameIdCacheFile(romFile)
        if (gameIdCacheFile.exists()) {
            //从缓存文件中读取
            val gameId = getGameIdFromGameIdCacheFile(gameIdCacheFile)
            if (is3DSGameId(gameId)) {
                return gameId
            }
        }
        if (romFile.exists()) {
            //从rom游戏文件中读取
            val romName = getGameIdFromFile(romFilePath)
            if (is3DSGameId(romName)) {
                return romName
            }
        }
        //只能从文件的路径中取了，不一定正确
        val romName = getGameIdFromRomFilePath(romFile)
        return if (is3DSGameId(romName)) {
            romName
        } else null
    }

    /**
     * 从缓存文件读gameId
     */
    fun getGameIdFromGameIdCacheFile(romNameCacheFile: File): String? {
        if (!romNameCacheFile.exists()) {
            return null
        }
        return IOUtil.readFile2String(romNameCacheFile)
    }

    /**
     * 保存gameId到缓存文件
     */
    fun saveGameId2GameIdCacheFile(romFile: File, gameId: String) {
        if (!is3DSGameId(gameId)) {
            return
        }
        IOUtil.writeFileFromString(getGameIdCacheFile(romFile), gameId)
    }

    /**
     * 从文件中取16位游戏ID
     *
     * @param filePath 文件路径
     */
    fun getGameIdFromFile(filePath: String?): String? {
        if (filePath.isNullOrEmpty()) {
            return null
        }
        val isZip = OtherUtil.getFileExtension(filePath).equals("zip", true)
        if (isZip) { //压缩包
            var zip: ZipFile? = null
            try {
                zip = ZipFile(filePath, "GBK")
                //获取压缩包的所有文件
                val validFiles = ArrayList<ZipEntry>()
                zip.entries.iterator().forEach {
                    val entryExtension = OtherUtil.getFileExtension(it.name)
                    if (CitraUtil.is3DSExtension(entryExtension)) {
                        validFiles.add(it)
                    }
                }
                if (validFiles.isEmpty()) {
                    return null
                }
                //按文件大小从大到小排序
                validFiles.sortWith { o1: ZipEntry, o2: ZipEntry ->
                    val diff = o2.size - o1.size
                    when {
                        diff > 0 -> {
                            1
                        }

                        diff < 0 -> {
                            -1
                        }

                        else -> {
                            0
                        }
                    }
                }
                validFiles.forEach {
                    val gameId = getGameIdFromGameFile(
                        BufferedInputStream(zip.getInputStream(it))
                    )
                    if (is3DSGameId(gameId)) {
                        return gameId
                    }
                }
            } catch (e: IOException) {
                e.printStackTrace()
            } finally {
                if (zip != null) {
                    try {
                        zip.close()
                    } catch (e: IOException) {
                        e.printStackTrace()
                    }
                }
            }
        } else { //单文件
            val gameId = getGameIdFromGameFile(BufferedInputStream(FileInputStream(filePath)))
            if (is3DSGameId(gameId)) {
                return gameId
            }
        }
        return null
    }

    /**
     * 从游戏文件里面提取游戏ID
     * 补丁 DLC 跟游戏ID不一样
     *
     * @param inputStream 输入流
     */
    fun getGameIdFromGameFile(inputStream: BufferedInputStream): String? {
        val gameId: String
        var isFind = false
        var tagStr = ""
        try {
            val bufSize = 1024
            val buffer = ByteArray(bufSize)
            while (-1 != inputStream.read(buffer, 0, bufSize)) {
                var hexString = IOUtil.bytes2HexString(buffer)
                if (!isFind) {
                    if (hexString.contains(GAME_ID_HEX_TAG)) {
                        val index = hexString.indexOf(GAME_ID_HEX_TAG)
                        if (index + 32 > hexString.length) {
                            isFind = true
                            tagStr = hexString
                        } else {
                            gameId = findGameId(hexString)
                            return gameId
                        }
                    }
                } else {
                    hexString = tagStr + hexString
                    gameId = findGameId(hexString)
                    return gameId
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            try {
                inputStream.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        return null
    }

    /**
     * 找GameId
     * @param hexString 16进制字符串
     */
    private fun findGameId(hexString: String): String {
        val index = hexString.indexOf(GAME_ID_HEX_TAG)
        var id = hexString.substring(index + 16, index + 32)
        var gameId = ""
        for (i in 8 downTo 1) {
            gameId += id.substring(id.length - 2)
            id = id.substring(0, id.length - 2)
        }
        return gameId
    }

    /**
     * 从Rom文件的路径取GameId
     * 25game/emuGame/3DS/00040000001d1800/xxxx.zip
     */
    fun getGameIdFromRomFilePath(romFile: File): String? {
        val parentFile = romFile.getParentFile() ?: return null
        return parentFile.getName()
    }

    /**
     * gameId的缓存，用于多模拟器互通
     *
     * @param romFile 盒子传递的游戏文件的路径 可能文件已经删除了
     */
    fun getGameIdCacheFile(romFile: File): File {
        val parentFile = romFile.getParentFile()
        return File(parentFile, ".romNameCache.aiwu")
    }

    /**
     * 判断16位ID是否是游戏
     */
    fun is3DSGameId(id: String?): Boolean {
        if (id == null || id.length != 16) {
            return false
        }
        return id.startsWith("00040000") || id.startsWith("00040010") || id.startsWith("00040030")
    }
}